package com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.css.bpm.platform.utils.*;
import com.css.zfzx.fxpg.common.utils.AreaBoundaryUtil;
import com.css.zfzx.fxpg.common.utils.BeanUtil;
import com.css.zfzx.fxpg.common.utils.CheckObjFields;
import com.css.zfzx.fxpg.common.utils.VectorDataUtil;
import com.css.zfzx.fxpg.modules.boundary.Point;
import com.css.zfzx.fxpg.modules.boundary.repository.BoundaryNativeRepository;
import com.css.zfzx.fxpg.modules.boundary.repository.entity.BoundaryEntity;
import com.css.zfzx.fxpg.modules.boundary.viewobjects.BoundaryQueryParams;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.repository.FxEconomicLossEvaluationMapImport;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.repository.FxEconomicLossEvaluationMapNativeRepository;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.repository.FxEconomicLossEvaluationMapRepository;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.repository.entity.FxEconomicLossEvaluationMapEntity;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.service.FxEconomicLossEvaluationMapService;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.viewobjects.FxEconomicLossEvaluationMapQueryParams;
import com.css.zfzx.fxpg.modules.evaluationmap.economicLoss.viewobjects.FxEconomicLossEvaluationMapVo;
import com.css.zfzx.fxpg.modules.popgdp.repository.FxPopGDPNativeRepository;
import com.css.zfzx.fxpg.modules.popgdp.repository.entity.FxPopGDPEntity;
import com.css.zfzx.fxpg.modules.popgdp.viewobjects.FxPopGDPQueryParams;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author andy
 * @date 2021-01-26
 */
@Service
@Slf4j
public class FxEconomicLossEvaluationMapServiceImpl implements FxEconomicLossEvaluationMapService {

	@Autowired
    private FxEconomicLossEvaluationMapRepository fxEconomicLossEvaluationMapRepository;
    @Autowired
    private FxEconomicLossEvaluationMapNativeRepository fxEconomicLossEvaluationMapNativeRepository;

    @Autowired
    private FxPopGDPNativeRepository fxPopGDPNativeRepository;

    @Autowired
    private FxEconomicLossEvaluationMapImport fxEconomicLossEvaluationMapImport;

    @Override
    public JSONObject queryFxEconomicLossEvaluationMaps(FxEconomicLossEvaluationMapQueryParams queryParams, int curPage, int pageSize) {
        Page<FxEconomicLossEvaluationMapEntity> fxEconomicLossEvaluationMapEntityPage = this.fxEconomicLossEvaluationMapNativeRepository.queryFxEconomicLossEvaluationMaps(queryParams, curPage, pageSize);
        JSONObject jsonObject = PlatformPageUtils.formatPageData(fxEconomicLossEvaluationMapEntityPage);
        return jsonObject;
    }

    @Override
    public JSONObject queryFxEconomicLossEvaluationMapsByFileName(FxEconomicLossEvaluationMapQueryParams queryParams, int curPage, int pageSize, String sort, String order) {
        if (!PlatformObjectUtils.isEmpty(sort) && sort.length() > 0) {
            sort = CheckObjFields.propertyChange(sort);
        }
        Page<FxEconomicLossEvaluationMapEntity> fxEconomicLossEvaluationMapEntityPage = this.fxEconomicLossEvaluationMapNativeRepository.queryFxEconomicLossEvaluationMapsByFileName(queryParams, curPage, pageSize, sort, order);
        JSONObject jsonObject = PlatformPageUtils.formatPageData(fxEconomicLossEvaluationMapEntityPage);
        return jsonObject;
    }

    @Override
    public FxEconomicLossEvaluationMapEntity getFxEconomicLossEvaluationMap(String id) {
        FxEconomicLossEvaluationMapEntity fxEconomicLossEvaluationMapEntity = this.fxEconomicLossEvaluationMapRepository.findById(id).orElse(null);
        return fxEconomicLossEvaluationMapEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FxEconomicLossEvaluationMapEntity saveFxEconomicLossEvaluationMap(FxEconomicLossEvaluationMapEntity fxEconomicLossEvaluationMapEntity) {
        String uuid = UUIDGenerator.getUUID();
        fxEconomicLossEvaluationMapEntity.setUuid(uuid);
        fxEconomicLossEvaluationMapEntity.setCreateUser(PlatformSessionUtils.getUserId());
        fxEconomicLossEvaluationMapEntity.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
        this.fxEconomicLossEvaluationMapRepository.save(fxEconomicLossEvaluationMapEntity);
        return fxEconomicLossEvaluationMapEntity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FxEconomicLossEvaluationMapEntity updateFxEconomicLossEvaluationMap(FxEconomicLossEvaluationMapEntity fxEconomicLossEvaluationMap) {
        fxEconomicLossEvaluationMap.setUpdateUser(PlatformSessionUtils.getUserId());
        fxEconomicLossEvaluationMap.setUpdateTime(PlatformDateUtils.getCurrentTimestamp());
        String id = fxEconomicLossEvaluationMap.getUuid();
        FxEconomicLossEvaluationMapEntity one = fxEconomicLossEvaluationMapRepository.findById(id).get();
        BeanUtil.copyPropertiesIgnoreNull(fxEconomicLossEvaluationMap, one);
        this.fxEconomicLossEvaluationMapRepository.save(one);
        return fxEconomicLossEvaluationMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteQhRiskEvaluationMaps(List<String> ids) {
        List<FxEconomicLossEvaluationMapEntity> qhFxEconomicLossEvaluationMapList = this.fxEconomicLossEvaluationMapRepository.findAllById(ids);
        if(!PlatformObjectUtils.isEmpty(qhFxEconomicLossEvaluationMapList) && qhFxEconomicLossEvaluationMapList.size() > 0) {
            for(FxEconomicLossEvaluationMapEntity qhFxEconomicLossEvaluationMap : qhFxEconomicLossEvaluationMapList) {
                this.fxEconomicLossEvaluationMapRepository.delete(qhFxEconomicLossEvaluationMap);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFxEconomicLossEvaluationMapsByFileName(List<String> fileNames) {
        for (int i = 0; i < fileNames.size(); i++) {
            FxEconomicLossEvaluationMapQueryParams queryParams = new FxEconomicLossEvaluationMapQueryParams();
            queryParams.setAffiliatedFileName(fileNames.get(i));
            List<FxEconomicLossEvaluationMapEntity> qhFxEconomicLossEvaluationMapList = this.fxEconomicLossEvaluationMapNativeRepository.listFxEconomicLossEvaluationMaps(queryParams);
            if(!PlatformObjectUtils.isEmpty(qhFxEconomicLossEvaluationMapList) && qhFxEconomicLossEvaluationMapList.size() > 0) {
                /*for(QhProbabilityEarthquakeDangerEntity qhSiteClassResult : qhSiteClassResultList) {
                    this.qhSiteClassResultRepository.delete(qhSiteClassResult);
                }*/
                //物理删
                //fxEconomicLossLevelMapImport.sqlBatchDeleteEntities(qhFxEconomicLossLevelMapList);
                fxEconomicLossEvaluationMapImport.sqlBatchLogicDeleteEntities(qhFxEconomicLossEvaluationMapList);
            }
        }
    }

    @Override
    public JSONObject getFxEconomicLossEvaluationMaps(FxEconomicLossEvaluationMapQueryParams queryParams) {
        List<FxEconomicLossEvaluationMapEntity> qhFxEconomicLossEvaluationMaps = this.fxEconomicLossEvaluationMapNativeRepository.listFxEconomicLossEvaluationMaps(queryParams);
        /*for (FxEconomicLossEvaluationMapEntity cemEntity : qhFxEconomicLossEvaluationMaps) {
            Map.Entry<String, Map<String, String>> city2areas = AreaBoundaryUtil.getCoordsByCityName(cemEntity.getProvince(), cemEntity.getCity());
            String coords = city2areas.getValue().get(cemEntity.getArea());
            cemEntity.setCoordinate(coords);
        }*/
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", qhFxEconomicLossEvaluationMaps);
        return jsonObject;
    }

    @Override
    public JSONObject getFxEconomicLossEvaluationMapsForSyntheticalDistrict(FxEconomicLossEvaluationMapQueryParams queryParams) {
        List<FxEconomicLossEvaluationMapEntity> qhFxEconomicLossEvaluationMaps = this.fxEconomicLossEvaluationMapNativeRepository.listFxEconomicLossEvaluationMaps(queryParams);
        for (FxEconomicLossEvaluationMapEntity cemEntity : qhFxEconomicLossEvaluationMaps) {
            String coords = getBoundaries(cemEntity.getProvince(), cemEntity.getCity(), cemEntity.getArea());
            cemEntity.setCoordinate(coords);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", qhFxEconomicLossEvaluationMaps);
        return jsonObject;
    }
    @Autowired
    private BoundaryNativeRepository boundaryNativeRepository;
    public String getBoundaries(String province, String city, String area) {
        BoundaryQueryParams queryParams = new BoundaryQueryParams();
        queryParams.setType("1");
        queryParams.setLevel("2");
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setName(area);
        List<BoundaryEntity> boundaryEntities = this.boundaryNativeRepository.listBoundaries(queryParams);
        if (boundaryEntities.size() == 1) {
            String coords = boundaryEntities.get(0).getCoordinate();
            if (coords == null) return "";
            coords = coords.substring(coords.indexOf("(((") + 3, coords.lastIndexOf(")))") - 1);
            coords = coords.replace(")), ((", "|");
            coords = coords.replace("), (", "#");
            coords = coords.replace(", ", ";");
            coords = coords.replace(" ", ",");
            return coords;
        }
        return "";
    }

    @Override
    public String importTIFFileData(String filePath, String province, String city, String area, String condition, double economicLossNum, String coordinate, String lossGridData) {
        String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length() - 4);
        // 返回的消息
        StringBuilder returnMsg = new StringBuilder();
        List<FxEconomicLossEvaluationMapVo> scrVOs = new ArrayList<FxEconomicLossEvaluationMapVo>();

        String lsGDp = getGDPOfArea(province, city, area);
        if (lsGDp == null) return "获取" + province + city + area + "GDP数据失败, 请检查GDP数据是否存在!";

        deleteFxEconomicLossEvaluationMapData(province, city, area, condition);

        FxEconomicLossEvaluationMapVo clmVO = new FxEconomicLossEvaluationMapVo();
        clmVO.setProvince(province);
        clmVO.setCity(city);
        clmVO.setArea(area);
        clmVO.setAffiliatedFileName(fileName);
        clmVO.setEarthquakeRisk(condition);//(地震危险性 0:50年超越概率2%分区, 1:50年超越概率10%分区, 2:50年超越概率63%分区, 3:100年超越概率1%分区)
        clmVO.setSum(economicLossNum);//(tif文件中经济损失)
        double ratio = economicLossNum / Double.parseDouble(lsGDp);
        clmVO.setLevel(VectorDataUtil.getRiskLevelByTIFValue(ratio, "0"));//(经济损失对应的风险等级)
        clmVO.setCoordinate(coordinate);
        clmVO.setRatio(String.valueOf(ratio));
        clmVO.setGridData(lossGridData);
        clmVO.setExtend1("CGCS2000");

        scrVOs.add(clmVO);
        try {
            // 批量新增
            this.saveData(scrVOs);
            returnMsg.append("成功导入" + scrVOs.size() + "条数据.");
            return returnMsg.toString();
        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
            return "插入或更新数据出现错误: <br/>" + e.getMessage();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "数据导入失败, 服务器内部出现异常!";
        }
    }

    private void saveData(List<FxEconomicLossEvaluationMapVo> list) throws Exception {
        List<FxEconomicLossEvaluationMapEntity> clms = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            FxEconomicLossEvaluationMapEntity cemEntity = new FxEconomicLossEvaluationMapEntity();
            FxEconomicLossEvaluationMapVo clmVO = list.get(i);
            // 将VO数据映射拷贝到库表中
            BeanUtils.copyProperties(clmVO, cemEntity);
            cemEntity.setIsValid("1");
            clms.add(cemEntity);
            //saveOrUpdate(scrEntity);
        }
        fxEconomicLossEvaluationMapImport.sqlBatchSaveEntities(clms);
    }

    @Override
    public void saveOrUpdate(FxEconomicLossEvaluationMapEntity rlmEntity) {
        FxEconomicLossEvaluationMapQueryParams queryParams = new FxEconomicLossEvaluationMapQueryParams();
        queryParams.setProvince(rlmEntity.getProvince());
        queryParams.setCity(rlmEntity.getCity());
        queryParams.setArea(rlmEntity.getArea());
        List<FxEconomicLossEvaluationMapEntity> clmEntities = fxEconomicLossEvaluationMapNativeRepository.listFxEconomicLossEvaluationMaps(queryParams);
        // 若查到数据为空，则新增
        if (CollectionUtils.isEmpty(clmEntities)) {
            this.saveFxEconomicLossEvaluationMap(rlmEntity);
        } else {
            if (clmEntities.size() == 1) {
                FxEconomicLossEvaluationMapEntity sourceProvinceEntity = clmEntities.get(0);
                BeanUtil.copyPropertiesIgnoreNull(rlmEntity, sourceProvinceEntity);
                this.updateFxEconomicLossEvaluationMap(sourceProvinceEntity);
            } else {
                throw new RuntimeException("库中该数据最多一条，请管理员清理数据库冗余数据！");
            }
        }
    }

    private void deleteFxEconomicLossEvaluationMapData(String province, String city, String area, String earthquakeRisk) {
        FxEconomicLossEvaluationMapQueryParams queryParams = new FxEconomicLossEvaluationMapQueryParams();
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setEarthquakeRisk(earthquakeRisk);
        List<FxEconomicLossEvaluationMapEntity> list = fxEconomicLossEvaluationMapNativeRepository.listFxEconomicLossEvaluationMaps(queryParams);
        if (list.size() > 0) fxEconomicLossEvaluationMapImport.sqlBatchDeleteEntities(list);
    }

    @Override
    public String judgeFileParams(String[] datas) {
        String str = "";
        Set<String> set = new HashSet<String>(Arrays.asList(datas));
        if(!set.contains("A")){
            str += "A,";
        }
        if(!set.contains("B")){
            str += "B,";
        }
        if(!set.contains("C")){
            str += "C,";
        }
        return str;
    }

    private String judgeFieldParams(List<List<Object>> list) {
        String str = "";
        for (int i = 0; i < list.size(); i++) {
            List<Object> values = list.get(i);
            //for (int j = 0; j < values.size(); j++) {
            for (int j = 0; j < 2; j++) {
                if ("".equals(values.get(j))) {
                    str += "第 " + i + " 条数据第 " + j + " 个字段数据为空.<br/>";
                }
            }
        }
        return str;
    }

    private String getGDPOfArea (String province, String city, String area) {
        FxPopGDPQueryParams queryParams = new FxPopGDPQueryParams();
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        List<FxPopGDPEntity> pgs = fxPopGDPNativeRepository.getFxPopGDPs(queryParams, null);
        if (pgs.size() == 1) return pgs.get(0).getLs_GDP();
        return null;
    }

    @Override
    public String checkPointIsInDistrict(String province, String city, String area, String rasterCoordinate) {
        BoundaryQueryParams queryParams = new BoundaryQueryParams();
        queryParams.setType("1");
        queryParams.setLevel("2");
        queryParams.setProvince(province);
        queryParams.setCity(city);
        queryParams.setArea(area);
        queryParams.setName(area);
        List<BoundaryEntity> boundaryEntities = this.boundaryNativeRepository.listBoundaries(queryParams);
        if (boundaryEntities.size() == 1) {
            BoundaryEntity boundaryEntity = boundaryEntities.get(0);
            String coordinate = boundaryEntity.getCoordinate();
            if (coordinate == null || "".equals(coordinate)) {
                return "NoDistrictBoundaryData";
            } else {
                coordinate = coordinate.substring(coordinate.indexOf("(((") + 3, coordinate.lastIndexOf(")))"));
                coordinate = coordinate.replace(")), ((", "|");
                coordinate = coordinate.replace("), (", "#");
                List<Point[]> boundaries = new ArrayList<>();
                String[] coordinates = StringUtils.split(coordinate, "|");
                for (int j = 0; j < coordinates.length; j++) {
                    String[] subGeometries = coordinates[j].split("#");
                    for (int k = 0; k < subGeometries.length; k++) {
                        String[] lonLats = subGeometries[k].split(", ");
                        Point[] points = new Point[lonLats.length];
                        for (int i = 0;i < lonLats.length;i++) {
                            String[] lonLat = lonLats[i].split(" ");
                            Point point = new Point();
                            point.x = Double.parseDouble(lonLat[0]);
                            point.y = Double.parseDouble(lonLat[1]);
                            points[i] = point;
                        }
                        boundaries.add(points);
                    }

                }

                int flag = 0;
                List<Point[]> geometries = parseWktCoordinate(rasterCoordinate);
                for (int j = 0; j < geometries.size(); j++) {
                    Point[] rectanglePoints = geometries.get(j);
                    flag = 0;
                    for (int m = 0; m < boundaries.size(); m++) {
                        Point[] boundary = boundaries.get(m);
                        if (AreaBoundaryUtil.isPolygonsOverlap(rectanglePoints, boundary)) {
                            flag++;
                            break;
                        } else {
                            boolean f = false;
                            for (int i = 0; i < rectanglePoints.length; i++) {
                                for (int k = 0; k < boundary.length; k++) {
                                    if (checkValue(rectanglePoints[i].x, boundary[k].x) || checkValue(rectanglePoints[i].y, boundary[k].y)) {
                                        flag++;
                                        f = true;
                                        break;
                                    }
                                }
                                if (f) break;
                            }
                        }
                    }
                    if (flag == 0) return "false";
                }
            }
        } else if (boundaryEntities.size() == 0) {
            return "NoDistrictBoundaryData";
        } else {
            return "DistrictBoundaryDataRedundance";
        }
        return "true";
    }
    private List<Point[]> parseWktCoordinate(String coordinate) {

        List<Point[]> geometriesList = new ArrayList<>();

        String[] rectangles = StringUtils.split (coordinate, "|");
        for (int i = 0; i < rectangles.length; i++) {
            String[] coords = rectangles[i].split (";");
            Point[] points = new Point[coords.length];
            for (int j = 0; j < coords.length; j++) {
                String[] lonLat = coords[j].split(" ");
                double lon = Double.parseDouble(lonLat[0]), lat = Double.parseDouble(lonLat[1]);
                Point point = new Point(lon, lat);
                points[j] = point;
            }
            geometriesList.add(points);
        }
        return geometriesList;
    }
    private boolean checkValue(double value1, double value2) {
        double thresh = 30;
        double det = Math.abs(value1 - value2);
        if (det >= 1) return false;
        det *= 60;
        if (det >= 1) return false;
        det *= 60;
        if (det <= thresh) return true;
        return false;
    }

    @Override
    public Long lookUpFxEconomicLossEvaluationMaps(FxEconomicLossEvaluationMapQueryParams queryParams) {
        Long count = this.fxEconomicLossEvaluationMapNativeRepository.lookUpFxEconomicLossEvaluationMaps(queryParams);
        return count;
    }

}
